/*
 * @Author: 
 * @Date: 2024-12-02 14:49:04
 * @LastEditor: zhuxiaoyi
 * @LastEditTime: 2024-12-02 15:58:37
 * @Description: 
 */
/*
 * @Author: 
 * @Date: 2024-12-02
 * @LastEditor: zhuxiaoyi
 * @LastEditTime: 2024-12-02 15:56:09
 * @Description: Token Service - 管理访问令牌和刷新令牌
 */
import { Provide, Config } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { Token } from '../entity/token.entity';
import * as jwt from 'jsonwebtoken';

@Provide()
export class TokenService {
  @Config('jwt')
  jwtConfig; // 注入 JWT 配置

  @InjectEntityModel(Token)
  TokenModel: Repository<Token>; // 注入 Token 实体的存储库

  /**
   * 生成访问令牌和刷新令牌
   * @param userId 用户 ID
   * @returns 返回访问令牌和刷新令牌
   */
  async generateTokens(userId: number): Promise<{ accessToken: string; refreshToken: string }> {
    const accessToken = jwt.sign({ userId }, this.jwtConfig.secret, { expiresIn: this.jwtConfig.expiresIn });
    const refreshToken = jwt.sign({ userId }, this.jwtConfig.secret, { expiresIn: this.jwtConfig.refreshExpiresIn });

    // 保存令牌到数据库
    const newToken = this.TokenModel.create({
      userId,
      token: accessToken,
      refreshToken,
      expiresAt: new Date(Date.now() + this._parseExpirationTime(this.jwtConfig.expiresIn)),
    });
    await this.TokenModel.save(newToken);

    return { accessToken, refreshToken };
  }

  /**
   * 验证访问令牌
   * @param token 访问令牌
   * @returns 验证结果，包含有效性和用户 ID（如果有效）
   */
  async verifyAccessToken(token: string): Promise<{ valid: boolean; userId?: string }> {
    try {
      const decoded = jwt.verify(token, this.jwtConfig.secret) as { userId: string };
      return { valid: true, userId: decoded.userId };
    } catch (error) {
      console.error('Token verification failed:', error.message);
      return { valid: false };
    }
  }

  /**
   * 刷新令牌
   * @param oldRefreshToken 旧的刷新令牌
   * @returns 新的访问令牌和刷新令牌，或 null（刷新失败）
   */
  async refreshToken(oldRefreshToken: string): Promise<{ accessToken: string; refreshToken: string } | null> {
    try {
      // 验证刷新令牌
      const decoded = jwt.verify(oldRefreshToken, this.jwtConfig.secret) as { userId: number };
      const existingToken = await this.TokenModel.findOne({ where: { refreshToken: oldRefreshToken } });
      if (!existingToken) {
        console.warn('Refresh token not found in database.');
        return null;
      }

      // 生成新的令牌
      const { accessToken, refreshToken } = await this.generateTokens(decoded.userId);

      // 删除旧的刷新令牌记录
      await this.TokenModel.remove(existingToken);

      return { accessToken, refreshToken };
    } catch (error) {
      console.error('Refresh token failed:', error.message);
      return null;
    }
  }

  /**
   * 撤销所有令牌
   * @param userId 用户 ID
   * @returns 是否撤销成功
   */
  async revokeTokens(userId: number): Promise<boolean> {
    try {
      const result = await this.TokenModel.delete({ userId });
      return result.affected > 0;
    } catch (error) {
      console.error('Failed to revoke tokens:', error.message);
      return false;
    }
  }

  /**
   * 解析过期时间（支持如 "1h", "7d" 格式）
   * @param expiresIn 过期时间
   * @returns 以毫秒为单位的时间
   */
  private _parseExpirationTime(expiresIn: string): number {
    const unit = expiresIn.slice(-1);
    const value = parseInt(expiresIn.slice(0, -1), 10);
    switch (unit) {
      case 'h':
        return value * 60 * 60 * 1000; // 小时转毫秒
      case 'd':
        return value * 24 * 60 * 60 * 1000; // 天转毫秒
      case 'm':
        return value * 60 * 1000; // 分钟转毫秒
      default:
        return value * 1000; // 默认秒转毫秒
    }
  }
}
